-
-
Notifications
You must be signed in to change notification settings - Fork 576
fix: resolve several drag & drop issues #1845
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
@blocknote/ariakit
@blocknote/code-block
@blocknote/core
@blocknote/mantine
@blocknote/react
@blocknote/server-util
@blocknote/shadcn
@blocknote/xl-ai
@blocknote/xl-docx-exporter
@blocknote/xl-email-exporter
@blocknote/xl-multi-column
@blocknote/xl-odt-exporter
@blocknote/xl-pdf-exporter
commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
A unified, document-level drag & drop implementation to handle cross-editor operations by synthesizing events based on proximity, replacing per-instance handlers and resolving cursor/display issues.
- Replaced legacy
onDrop
/onDragEnd
inSideMenuPlugin
withonDragOver
,onDrop
, andonDragEnd
that usegetDragEventContext
- Added
findClosestEditorElement
,dispatchSyntheticEvent
, andcloseDropCursor
for synthetic event management within 250px thresholds - Bumped
prosemirror-dropcursor
from 1.8.1 to 1.8.2
Reviewed Changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 3 comments.
File | Description |
---|---|
packages/core/src/extensions/SideMenu/SideMenuPlugin.ts | Reworked drag & drop logic: removed old handlers, added proximity detection, context extraction, and synthetic event dispatchers |
packages/core/package.json | Updated prosemirror-dropcursor dependency to ^1.8.2 |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (2)
packages/core/src/extensions/SideMenu/SideMenuPlugin.ts:432
- The new
getDragEventContext
logic contains multiple edge cases (origin vs. drop point vs. bounds). Consider adding unit tests to cover each scenario for regression safety.
getDragEventContext = (event: DragEvent) => {
packages/core/src/extensions/SideMenu/SideMenuPlugin.ts:517
- The selection collapse now uses
selection.anchor
, which differs from the originalselection.to
behavior and may shift the drop insertion point. Consider restoringthis.pmView.state.tr.selection.to
to match prior logic.
TextSelection.create(
const evt = new Event(event.type as "dragover", event) as any; | ||
const editorBoundingBox = this.pmView.dom.getBoundingClientRect(); | ||
evt.clientX = event.clientX; | ||
evt.clientY = event.clientY; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating synthetic drag/drop events with new Event
omits the native DragEvent
properties. Use new DragEvent(event.type, { ...eventInit })
to ensure dataTransfer
, coordinates, and default behavior are preserved.
const evt = new Event(event.type as "dragover", event) as any; | |
const editorBoundingBox = this.pmView.dom.getBoundingClientRect(); | |
evt.clientX = event.clientX; | |
evt.clientY = event.clientY; | |
const editorBoundingBox = this.pmView.dom.getBoundingClientRect(); | |
const evt = new DragEvent(event.type, { | |
clientX: event.clientX, | |
clientY: event.clientY, | |
dataTransfer: event.dataTransfer, | |
}); |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried to refactor this, but there is something finicky with drag events that they drop the data transfer
const closestEditor = this.findClosestEditorElement(event); | ||
|
||
// We arbitrarily decide how far is "too far" from the closest editor to be considered a drop point | ||
if (!closestEditor || closestEditor.distance > 250) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The 250
px threshold is a magic number. Extract it into a named constant (e.g., MAX_PROXIMITY_PX
) to clarify its purpose and simplify future adjustments.
if (!closestEditor || closestEditor.distance > 250) { | |
if (!closestEditor || closestEditor.distance > MAX_PROXIMITY_PX) { |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@matthewlipski not sure what the best thing to do here would be. Likely a percentage like you are using elsewhere in the file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great!! The comments make things so much clearer :)
Some UX glitches I encountered when dragging in a single editor:
see gif, in order of appearance (I think all of these don't occur on the live version):
- dragging to side+below an editor moves drag line to top (instead of at bottom)
- dropping a block opens the formatting toolbar
- dropping a block to the side doesn't seem to work
* - If the dragover event is outside the bounds of the current editor, then it will dispatch a synthetic dragleave event to the current editor | ||
* (which will trigger the drop-cursor to be removed from the current editor) | ||
* | ||
* The synthetic event is a necessary evil because we do not control prosemirror-dropcursor to be able to show the drop-cursor within the range we want |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it be a lot easier if we fork dropcursor?
normally I'd not suggest this, but given we already have an alternative dropcursor plugin for mult-column, it might be a cleaner solution?
@@ -93,7 +93,7 @@ | |||
"@tiptap/pm": "^2.12.0", | |||
"emoji-mart": "^5.6.0", | |||
"hast-util-from-dom": "^5.0.1", | |||
"prosemirror-dropcursor": "^1.8.1", | |||
"prosemirror-dropcursor": "^1.8.2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we'll probably need to update our multi-column dropcursor as well (see comment below)
} | ||
|
||
if ( | ||
this.sideMenuDetection === "editor" || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did we drop sideMenuDetection
? then we also need to remove it from editor options / docs / etc
This adjusts the logic for drag & drop (especially between editor instances) to handle things better. It is surprisingly complicated to get drag & drop to work nicely across editor instances.
The problem is that each editor instance is listening for events on it's own HTMLElement, but we want to support dragging near an element, and allowing the drop to occur anyway (despite not actually dropping on the element, just near it). To do this, we have to fiddle with the event handling (since we still want for each editor instance to only listen for drag & drop events on it's own element) such that we create synthetic events to trick the editor into doing what the user intended, but did not actually do.
We need to fire these synthetic events under very specific circumstances:
But, now that we are sometimes triggering these synthetic events, Prosemirror does not have the full-scope of what we've implemented so when dragging & dropping across different editor instances we need to either:
This leads to some very complex logic & several edge cases. For example, there are differences between dragging text vs. using the side menu handle.
I also want to fix the drag previews in this PR(This seems to not be possible in firefox)TODO